"use client"

import type React from "react"
import { useState, useCallback, useEffect, useRef } from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { ScrollArea } from "@/components/ui/scroll-area"
import { Badge } from "@/components/ui/badge"
import { Textarea } from "@/components/ui/textarea"
import { useToast } from "@/hooks/use-toast"
import { mockData, type WorkflowNode, type WorkflowEdge } from "@/lib/mock-data"
import {
  Save,
  Play,
  Zap,
  MessageSquare,
  Database,
  Code,
  GitBranch,
  Filter,
  Mail,
  FileText,
  Globe,
  Trash2,
  Download,
  Copy,
  type LucideIcon,
} from "lucide-react"
import { getNodeIcon } from "@/lib/get-node-icon"

// Define node configurations for Dify
const difyNodeConfigs = [
  { id: "trigger", type: "trigger", label: "触发器", iconName: "Zap", category: "基础" },
  { id: "llm", type: "llm", label: "LLM", iconName: "MessageSquare", category: "AI" },
  { id: "knowledge", type: "knowledge", label: "知识库", iconName: "Database", category: "AI" },
  { id: "code", type: "code", label: "代码", iconName: "Code", category: "逻辑" },
  { id: "condition", type: "condition", label: "条件", iconName: "GitBranch", category: "逻辑" },
  { id: "template", type: "template", label: "模板", iconName: "FileText", category: "数据" },
  { id: "http", type: "http", label: "HTTP 请求", iconName: "Globe", category: "集成" },
]

// Define node configurations for Coze
const cozeNodeConfigs = [
  { id: "start", type: "start", label: "开始", iconName: "Zap", category: "基础" },
  { id: "llm", type: "llm", label: "大模型", iconName: "MessageSquare", category: "AI" },
  { id: "plugin", type: "plugin", label: "插件", iconName: "Database", category: "工具" },
  { id: "code", type: "code", label: "代码块", iconName: "Code", category: "逻辑" },
  { id: "branch", type: "branch", label: "分支", iconName: "GitBranch", category: "逻辑" },
  { id: "variable", type: "variable", label: "变量", iconName: "Filter", category: "数据" },
  { id: "end", type: "end", label: "结束", iconName: "FileText", category: "基础" },
]

const iconMap: Record<string, LucideIcon> = {
  Zap,
  MessageSquare,
  Database,
  Code,
  GitBranch,
  Filter,
  Mail,
  FileText,
  Globe,
}

type HandlePosition = "top" | "right" | "bottom" | "left"

interface ConnectionHandle {
  nodeId: string
  position: HandlePosition
  x: number
  y: number
}

interface WorkflowBuilderProps {
  workflowId?: string
}

export function WorkflowBuilder({ workflowId }: WorkflowBuilderProps) {
  const { toast } = useToast()
  const [isLoading, setIsLoading] = useState(true)
  const [workflowName, setWorkflowName] = useState("未命名工作流")
  const [workflowType, setWorkflowType] = useState<"dify" | "coze" | "langgraph">("dify")
  const [selectedNode, setSelectedNode] = useState<WorkflowNode | null>(null)
  const [canvasNodes, setCanvasNodes] = useState<WorkflowNode[]>([])
  const [edges, setEdges] = useState<WorkflowEdge[]>([])
  const [langGraphCode, setLangGraphCode] = useState("")
  const [connectingFrom, setConnectingFrom] = useState<ConnectionHandle | null>(null)
  const [tempConnectionEnd, setTempConnectionEnd] = useState<{ x: number; y: number } | null>(null)
  const [hoveredHandle, setHoveredHandle] = useState<ConnectionHandle | null>(null)
  const [draggingNode, setDraggingNode] = useState<string | null>(null)
  const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 })
  const canvasRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    // Use setTimeout to defer localStorage access until after hydration
    const timer = setTimeout(() => {
      if (workflowId) {
        try {
          const workflow = mockData.getWorkflow(workflowId)
          if (workflow) {
            setWorkflowName(workflow.name)
            setWorkflowType(workflow.type)
            setCanvasNodes(workflow.nodes || [])
            setEdges(workflow.edges || [])
            setLangGraphCode(workflow.code || getDefaultLangGraphCode())
          }
        } catch (error) {
          console.error("[v0] Error loading workflow:", error)
          setLangGraphCode(getDefaultLangGraphCode())
        }
      } else {
        setLangGraphCode(getDefaultLangGraphCode())
      }
      setIsLoading(false)
    }, 0)

    return () => clearTimeout(timer)
  }, [workflowId])

  // Select node configurations based on workflow type
  const nodeConfigs = workflowType === "dify" ? difyNodeConfigs : cozeNodeConfigs

  function getDefaultLangGraphCode() {
    return `from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
from operator import add

class State(TypedDict):
    messages: Annotated[list[str], add]
    
def process_input(state: State):
    """处理输入节点"""
    return {"messages": ["Input processed"]}

def llm_node(state: State):
    """LLM 处理节点"""
    # 这里调用 LLM API
    response = "LLM response based on: " + str(state["messages"])
    return {"messages": [response]}

def output_node(state: State):
    """输出节点"""
    return {"messages": ["Output: " + state["messages"][-1]]}

# 创建工作流图
workflow = StateGraph(State)

# 添加节点
workflow.add_node("input", process_input)
workflow.add_node("llm", llm_node)
workflow.add_node("output", output_node)

# 设置入口点
workflow.set_entry_point("input")

# 添加边（连接节点）
workflow.add_edge("input", "llm")
workflow.add_edge("llm", "output")
workflow.add_edge("output", END)

# 编译工作流
app = workflow.compile()

# 运行工作流
if __name__ == "__main__":
    result = app.invoke({"messages": []})
    print(result)`
  }

  const handleDragStart = (e: React.DragEvent, config: any) => {
    e.dataTransfer.setData("nodeType", config.type)
    e.dataTransfer.setData("nodeLabel", config.label)
    e.dataTransfer.setData("iconName", config.iconName)
    e.dataTransfer.effectAllowed = "copy"
  }

  const handleDrop = useCallback(
    (e: React.DragEvent) => {
      e.preventDefault()
      const nodeType = e.dataTransfer.getData("nodeType")
      const nodeLabel = e.dataTransfer.getData("nodeLabel")
      const iconName = e.dataTransfer.getData("iconName")

      const rect = e.currentTarget.getBoundingClientRect()
      const x = e.clientX - rect.left
      const y = e.clientY - rect.top

      const newNode: WorkflowNode = {
        id: `${nodeType}-${Date.now()}`,
        type: nodeType,
        label: nodeLabel,
        x,
        y,
        config: { iconName },
      }

      setCanvasNodes([...canvasNodes, newNode])
      toast({
        title: "节点已添加",
        description: `${nodeLabel} 已添加到画布`,
      })
    },
    [canvasNodes, toast],
  )

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault()
    e.dataTransfer.dropEffect = "copy"
  }

  const getHandlePosition = (node: WorkflowNode, position: HandlePosition): { x: number; y: number } => {
    const nodeWidth = 150
    const nodeHeight = 80

    switch (position) {
      case "top":
        return { x: node.x, y: node.y - nodeHeight / 2 }
      case "right":
        return { x: node.x + nodeWidth / 2, y: node.y }
      case "bottom":
        return { x: node.x, y: node.y + nodeHeight / 2 }
      case "left":
        return { x: node.x - nodeWidth / 2, y: node.y }
    }
  }

  const handleConnectionStart = (nodeId: string, position: HandlePosition, e: React.MouseEvent) => {
    e.stopPropagation()
    const node = canvasNodes.find((n) => n.id === nodeId)
    if (!node) return

    const handlePos = getHandlePosition(node, position)
    setConnectingFrom({
      nodeId,
      position,
      x: handlePos.x,
      y: handlePos.y,
    })
    setTempConnectionEnd(handlePos)
  }

  const handleCanvasMouseMove = useCallback(
    (e: React.MouseEvent) => {
      if (connectingFrom && canvasRef.current) {
        const rect = canvasRef.current.getBoundingClientRect()
        const x = e.clientX - rect.left
        const y = e.clientY - rect.top
        setTempConnectionEnd({ x, y })
      }

      if (draggingNode && canvasRef.current) {
        const rect = canvasRef.current.getBoundingClientRect()
        const x = e.clientX - rect.left - dragOffset.x
        const y = e.clientY - rect.top - dragOffset.y

        setCanvasNodes((nodes) =>
          nodes.map((node) =>
            node.id === draggingNode
              ? {
                  ...node,
                  x: Math.max(75, Math.min(rect.width - 75, x)),
                  y: Math.max(40, Math.min(rect.height - 40, y)),
                }
              : node,
          ),
        )
      }
    },
    [connectingFrom, draggingNode, dragOffset],
  )

  const handleConnectionEnd = (targetNodeId: string, targetPosition: HandlePosition, e: React.MouseEvent) => {
    e.stopPropagation()

    if (!connectingFrom || connectingFrom.nodeId === targetNodeId) {
      setConnectingFrom(null)
      setTempConnectionEnd(null)
      return
    }

    const newEdge: WorkflowEdge = {
      id: `edge-${Date.now()}`,
      source: connectingFrom.nodeId,
      target: targetNodeId,
      sourceHandle: connectingFrom.position,
      targetHandle: targetPosition,
    }

    setEdges([...edges, newEdge])
    setConnectingFrom(null)
    setTempConnectionEnd(null)

    toast({
      title: "连接成功",
      description: "节点已连接",
    })
  }

  const handleCanvasMouseUp = useCallback(() => {
    setDraggingNode(null)
    setConnectingFrom(null)
    setTempConnectionEnd(null)
  }, [])

  const handleDeleteNode = (nodeId: string, e: React.MouseEvent) => {
    e.stopPropagation()
    setCanvasNodes(canvasNodes.filter((n) => n.id !== nodeId))
    setEdges(edges.filter((e) => e.source !== nodeId && e.target !== nodeId))
    if (selectedNode?.id === nodeId) {
      setSelectedNode(null)
    }
    toast({
      title: "节点已删除",
      description: "节点及其连接已从画布中移除",
    })
  }

  const handleSave = () => {
    const workflowData = {
      name: workflowName,
      type: workflowType,
      nodes: canvasNodes,
      edges: edges,
      code: workflowType === "langgraph" ? langGraphCode : undefined,
    }

    if (workflowId) {
      mockData.updateWorkflow(workflowId, workflowData)
      toast({
        title: "保存成功",
        description: "工作流已更新",
      })
    } else {
      mockData.addWorkflow({
        ...workflowData,
        status: "draft",
        lastRun: "从未运行",
        createdAt: new Date().toISOString().split("T")[0],
      })
      toast({
        title: "保存成功",
        description: "新工作流已创建",
      })
    }
  }

  const handleTest = () => {
    toast({
      title: "测试运行中",
      description: "工作流正在执行测试...",
    })
    setTimeout(() => {
      toast({
        title: "测试完成",
        description: "工作流执行成功",
      })
    }, 2000)
  }

  // Export LangGraph code
  const handleExportCode = () => {
    const blob = new Blob([langGraphCode], { type: "text/plain" })
    const url = URL.createObjectURL(blob)
    const a = document.createElement("a")
    a.href = url
    a.download = `${workflowName.replace(/\s+/g, "_")}_workflow.py`
    document.body.appendChild(a)
    a.click()
    document.body.removeChild(a)
    URL.revokeObjectURL(url)
    toast({
      title: "导出成功",
      description: "LangGraph 代码已下载",
    })
  }

  // Copy code to clipboard
  const handleCopyCode = async () => {
    try {
      await navigator.clipboard.writeText(langGraphCode)
      toast({
        title: "复制成功",
        description: "代码已复制到剪贴板",
      })
    } catch (err) {
      toast({
        title: "复制失败",
        description: "请手动复制代码",
        variant: "destructive",
      })
    }
  }

  const handleNodeMouseDown = (nodeId: string, e: React.MouseEvent) => {
    // Only start dragging on left click, not double click
    if (e.detail === 2) return

    const node = canvasNodes.find((n) => n.id === nodeId)
    if (!node) return

    const rect = canvasRef.current?.getBoundingClientRect()
    if (!rect) return

    setDraggingNode(nodeId)
    setDragOffset({
      x: e.clientX - rect.left - node.x,
      y: e.clientY - rect.top - node.y,
    })
    e.stopPropagation()
  }

  const renderEdges = () => {
    return edges.map((edge) => {
      const sourceNode = canvasNodes.find((n) => n.id === edge.source)
      const targetNode = canvasNodes.find((n) => n.id === edge.target)

      if (!sourceNode || !targetNode) return null

      const sourcePos = getHandlePosition(sourceNode, edge.sourceHandle || "right")
      const targetPos = getHandlePosition(targetNode, edge.targetHandle || "left")

      const x1 = sourcePos.x
      const y1 = sourcePos.y
      const x2 = targetPos.x
      const y2 = targetPos.y

      const dx = x2 - x1
      const dy = y2 - y1
      const distance = Math.sqrt(dx * dx + dy * dy)

      const controlOffset = Math.min(distance * 0.5, 150)

      let controlX1 = x1
      let controlY1 = y1
      let controlX2 = x2
      let controlY2 = y2

      if (edge.sourceHandle === "right") controlX1 = x1 + controlOffset
      else if (edge.sourceHandle === "left") controlX1 = x1 - controlOffset
      else if (edge.sourceHandle === "top") controlY1 = y1 - controlOffset
      else if (edge.sourceHandle === "bottom") controlY1 = y1 + controlOffset

      if (edge.targetHandle === "right") controlX2 = x2 + controlOffset
      else if (edge.targetHandle === "left") controlX2 = x2 - controlOffset
      else if (edge.targetHandle === "top") controlY2 = y2 - controlOffset
      else if (edge.targetHandle === "bottom") controlY2 = y2 + controlOffset

      return (
        <g key={edge.id}>
          <path
            d={`M ${x1} ${y1} C ${controlX1} ${controlY1}, ${controlX2} ${controlY2}, ${x2} ${y2}`}
            stroke="hsl(var(--primary))"
            strokeWidth="3"
            fill="none"
            markerEnd="url(#arrowhead)"
            className="transition-all hover:stroke-primary/80"
            style={{ filter: "drop-shadow(0 1px 2px rgba(0,0,0,0.1))" }}
          />
          <circle
            cx={(x1 + x2) / 2}
            cy={(y1 + y2) / 2}
            r="12"
            fill="hsl(var(--background))"
            stroke="hsl(var(--primary))"
            strokeWidth="2"
            cursor="pointer"
            className="hover:fill-destructive hover:stroke-destructive transition-colors"
            onClick={(e) => {
              e.stopPropagation()
              setEdges(edges.filter((e) => e.id !== edge.id))
              toast({
                title: "连接已删除",
                description: "节点连接已移除",
              })
            }}
          />
          <text
            x={(x1 + x2) / 2}
            y={(y1 + y2) / 2}
            textAnchor="middle"
            dominantBaseline="middle"
            fontSize="14"
            fontWeight="bold"
            fill="hsl(var(--primary))"
            pointerEvents="none"
            className="select-none"
          >
            ×
          </text>
        </g>
      )
    })
  }

  const renderTempConnection = () => {
    if (!connectingFrom || !tempConnectionEnd) return null

    const x1 = connectingFrom.x
    const y1 = connectingFrom.y
    const x2 = tempConnectionEnd.x
    const y2 = tempConnectionEnd.y

    const dx = x2 - x1
    const dy = y2 - y1
    const distance = Math.sqrt(dx * dx + dy * dy)
    const controlOffset = Math.min(distance * 0.5, 150)

    let controlX1 = x1
    let controlY1 = y1

    if (connectingFrom.position === "right") controlX1 = x1 + controlOffset
    else if (connectingFrom.position === "left") controlX1 = x1 - controlOffset
    else if (connectingFrom.position === "top") controlY1 = y1 - controlOffset
    else if (connectingFrom.position === "bottom") controlY1 = y1 + controlOffset

    return (
      <path
        d={`M ${x1} ${y1} C ${controlX1} ${controlY1}, ${x2} ${y2}, ${x2} ${y2}`}
        stroke="hsl(var(--primary))"
        strokeWidth="3"
        strokeDasharray="8,4"
        fill="none"
        className="transition-all opacity-70 animate-pulse"
        style={{ filter: "drop-shadow(0 1px 2px rgba(0,0,0,0.1))" }}
      />
    )
  }

  const renderConnectionHandles = (node: WorkflowNode) => {
    const positions: HandlePosition[] = ["top", "right", "bottom", "left"]

    return positions.map((position) => {
      let style: React.CSSProperties = {
        position: "absolute",
        width: "14px",
        height: "14px",
        borderRadius: "50%",
        border: "3px solid hsl(var(--primary))",
        background: "hsl(var(--background))",
        cursor: "crosshair",
        zIndex: 10,
        opacity: 0,
        transition: "all 0.2s",
        boxShadow: "0 2px 4px rgba(0,0,0,0.1)",
      }

      switch (position) {
        case "top":
          style = { ...style, top: "-7px", left: "50%", transform: "translateX(-50%)" }
          break
        case "right":
          style = { ...style, right: "-7px", top: "50%", transform: "translateY(-50%)" }
          break
        case "bottom":
          style = { ...style, bottom: "-7px", left: "50%", transform: "translateX(-50%)" }
          break
        case "left":
          style = { ...style, left: "-7px", top: "50%", transform: "translateY(-50%)" }
          break
      }

      const isHovered = hoveredHandle?.nodeId === node.id && hoveredHandle?.position === position
      const isConnecting = connectingFrom !== null

      return (
        <div
          key={position}
          style={{
            ...style,
            opacity: isHovered || isConnecting ? 1 : undefined,
            background: isHovered ? "hsl(var(--primary))" : style.background,
            transform:
              position === "top" || position === "bottom"
                ? `translateX(-50%) ${isHovered ? "scale(1.2)" : ""}`
                : `translateY(-50%) ${isHovered ? "scale(1.2)" : ""}`,
          }}
          className="group-hover:opacity-100"
          onMouseDown={(e) => handleConnectionStart(node.id, position, e)}
          onMouseUp={(e) => handleConnectionEnd(node.id, position, e)}
          onMouseEnter={() => {
            const handlePos = getHandlePosition(node, position)
            setHoveredHandle({ nodeId: node.id, position, ...handlePos })
          }}
          onMouseLeave={() => setHoveredHandle(null)}
        />
      )
    })
  }

  if (isLoading) {
    return (
      <div className="h-[calc(100vh-8rem)] flex items-center justify-center">
        <div className="text-center space-y-2">
          <div className="h-8 w-8 border-4 border-primary border-t-transparent rounded-full animate-spin mx-auto" />
          <p className="text-sm text-muted-foreground">加载中...</p>
        </div>
      </div>
    )
  }

  return (
    <div className="h-[calc(100vh-8rem)] flex flex-col gap-4">
      {/* Toolbar */}
      <div className="flex items-center justify-between">
        <div className="flex items-center gap-4">
          <Input
            value={workflowName}
            onChange={(e) => setWorkflowName(e.target.value)}
            className="w-64 font-semibold"
          />
          <Tabs value={workflowType} onValueChange={(v) => setWorkflowType(v as any)}>
            <TabsList>
              <TabsTrigger value="dify">Dify</TabsTrigger>
              <TabsTrigger value="coze">Coze</TabsTrigger>
              <TabsTrigger value="langgraph">LangGraph</TabsTrigger>
            </TabsList>
          </Tabs>
        </div>
        <div className="flex items-center gap-2">
          {workflowType === "langgraph" && (
            <>
              <Button variant="outline" size="sm" onClick={handleCopyCode}>
                <Copy className="mr-2 h-4 w-4" />
                复制代码
              </Button>
              <Button variant="outline" size="sm" onClick={handleExportCode}>
                <Download className="mr-2 h-4 w-4" />
                导出代码
              </Button>
            </>
          )}
          <Button variant="outline" onClick={handleTest}>
            <Play className="mr-2 h-4 w-4" />
            测试运行
          </Button>
          <Button onClick={handleSave}>
            <Save className="mr-2 h-4 w-4" />
            保存
          </Button>
        </div>
      </div>

      {/* Main Content */}
      {workflowType === "langgraph" ? (
        // LangGraph code editor interface
        <div className="flex-1 grid grid-cols-[1fr_320px] gap-4 min-h-0">
          <Card className="flex flex-col">
            <CardHeader className="pb-3">
              <CardTitle className="text-base">LangGraph 代码编辑器</CardTitle>
              <CardDescription>编写 LangGraph 工作流代码</CardDescription>
            </CardHeader>
            <CardContent className="flex-1 p-0">
              <Textarea
                value={langGraphCode}
                onChange={(e) => setLangGraphCode(e.target.value)}
                className="h-full font-mono text-sm resize-none rounded-none border-0 focus-visible:ring-0"
                placeholder="输入 LangGraph 代码..."
              />
            </CardContent>
          </Card>

          <Card className="flex flex-col">
            <CardHeader className="pb-3">
              <CardTitle className="text-base">代码说明</CardTitle>
              <CardDescription>LangGraph 工作流指南</CardDescription>
            </CardHeader>
            <CardContent>
              <ScrollArea className="h-[calc(100vh-16rem)]">
                <div className="space-y-4 text-sm">
                  <div>
                    <h4 className="font-semibold mb-2">基本结构</h4>
                    <p className="text-muted-foreground">
                      LangGraph 工作流由状态图（StateGraph）、节点（Node）和边（Edge）组成。
                    </p>
                  </div>
                  <div>
                    <h4 className="font-semibold mb-2">定义状态</h4>
                    <code className="block bg-muted p-2 rounded text-xs">
                      class State(TypedDict):
                      <br />
                      &nbsp;&nbsp;messages: list[str]
                    </code>
                  </div>
                  <div>
                    <h4 className="font-semibold mb-2">添加节点</h4>
                    <code className="block bg-muted p-2 rounded text-xs">workflow.add_node("name", func)</code>
                  </div>
                  <div>
                    <h4 className="font-semibold mb-2">连接节点</h4>
                    <code className="block bg-muted p-2 rounded text-xs">workflow.add_edge("from", "to")</code>
                  </div>
                  <div>
                    <h4 className="font-semibold mb-2">运行工作流</h4>
                    <p className="text-muted-foreground">保存代码后，可以在本地或 LangGraph 环境中运行。</p>
                  </div>
                </div>
              </ScrollArea>
            </CardContent>
          </Card>
        </div>
      ) : (
        // Dify/Coze drag-and-drop interface
        <div className="flex-1 grid grid-cols-[280px_1fr_320px] gap-4 min-h-0">
          {/* Node Library */}
          <Card className="flex flex-col">
            <CardHeader className="pb-3">
              <CardTitle className="text-base">节点库</CardTitle>
              <CardDescription>拖拽节点到画布</CardDescription>
            </CardHeader>
            <CardContent className="flex-1 p-0">
              <ScrollArea className="h-full px-4 pb-4">
                <div className="space-y-4">
                  {Array.from(new Set(nodeConfigs.map((c) => c.category))).map((category) => (
                    <div key={category} className="space-y-2">
                      <h4 className="text-sm font-medium text-muted-foreground">{category}</h4>
                      <div className="space-y-1">
                        {nodeConfigs
                          .filter((config) => config.category === category)
                          .map((config) => {
                            const IconComponent = iconMap[config.iconName]
                            return (
                              <div
                                key={config.id}
                                draggable
                                onDragStart={(e) => handleDragStart(e, config)}
                                className="flex items-center gap-3 p-3 rounded-lg border bg-card hover:bg-accent cursor-move transition-colors"
                              >
                                <div className="h-8 w-8 rounded-md bg-primary/10 flex items-center justify-center flex-shrink-0">
                                  <IconComponent className="h-4 w-4 text-primary" />
                                </div>
                                <span className="text-sm font-medium">{config.label}</span>
                              </div>
                            )
                          })}
                      </div>
                    </div>
                  ))}
                </div>
              </ScrollArea>
            </CardContent>
          </Card>

          {/* Canvas */}
          <Card className="relative overflow-hidden">
            <div
              ref={canvasRef}
              onDrop={handleDrop}
              onDragOver={handleDragOver}
              onMouseMove={handleCanvasMouseMove}
              onMouseUp={handleCanvasMouseUp}
              onMouseLeave={handleCanvasMouseUp}
              onClick={() => setSelectedNode(null)}
              className="absolute inset-0 bg-[radial-gradient(#e5e7eb_1px,transparent_1px)] [background-size:16px_16px] dark:bg-[radial-gradient(#27272a_1px,transparent_1px)]"
            >
              <svg className="absolute inset-0 w-full h-full" style={{ zIndex: 1, pointerEvents: "none" }}>
                <defs>
                  <marker
                    id="arrowhead"
                    markerWidth="12"
                    markerHeight="12"
                    refX="11"
                    refY="6"
                    orient="auto"
                    markerUnits="strokeWidth"
                  >
                    <path d="M 0 0 L 12 6 L 0 12 z" fill="hsl(var(--primary))" />
                  </marker>
                </defs>
                <g style={{ pointerEvents: "all" }}>
                  {renderEdges()}
                  {renderTempConnection()}
                </g>
              </svg>

              {canvasNodes.length === 0 ? (
                <div className="absolute inset-0 flex items-center justify-center" style={{ zIndex: 2 }}>
                  <div className="text-center space-y-2">
                    <p className="text-muted-foreground">从左侧拖拽节点到此处开始构建工作流</p>
                    <Badge variant="outline">拖动节点调整位置 • 从节点边缘的连接点拖拽创建连线</Badge>
                  </div>
                </div>
              ) : (
                <div style={{ position: "relative", zIndex: 2 }}>
                  {canvasNodes.map((node) => {
                    const IconComponent = getNodeIcon(node)
                    const isSelected = selectedNode?.id === node.id
                    const isDragging = draggingNode === node.id

                    return (
                      <div
                        key={node.id}
                        style={{
                          position: "absolute",
                          left: node.x - 75,
                          top: node.y - 40,
                          cursor: isDragging ? "grabbing" : "grab",
                        }}
                        onClick={(e) => {
                          e.stopPropagation()
                          setSelectedNode(node)
                        }}
                        onMouseDown={(e) => handleNodeMouseDown(node.id, e)}
                        className={`w-[150px] p-3 rounded-lg border-2 bg-card hover:border-primary transition-all shadow-sm group ${
                          isSelected ? "border-primary ring-2 ring-primary/20" : ""
                        } ${isDragging ? "shadow-lg scale-105" : ""}`}
                      >
                        {renderConnectionHandles(node)}

                        <div className="flex items-center gap-2">
                          <div className="h-8 w-8 rounded-md bg-primary/10 flex items-center justify-center flex-shrink-0">
                            <IconComponent className="h-4 w-4 text-primary" />
                          </div>
                          <span className="text-sm font-medium truncate flex-1">{node.label}</span>
                          <Button
                            variant="ghost"
                            size="icon"
                            className="h-6 w-6 opacity-0 group-hover:opacity-100 transition-opacity"
                            onClick={(e) => handleDeleteNode(node.id, e)}
                            onMouseDown={(e) => e.stopPropagation()}
                          >
                            <Trash2 className="h-3 w-3" />
                          </Button>
                        </div>
                      </div>
                    )
                  })}
                </div>
              )}
            </div>
          </Card>

          {/* Properties Panel */}
          <Card className="flex flex-col">
            <CardHeader className="pb-3">
              <CardTitle className="text-base">节点属性</CardTitle>
              <CardDescription>{connectingFrom ? "拖拽到目标连接点" : "配置选中节点"}</CardDescription>
            </CardHeader>
            <CardContent className="flex-1">
              {connectingFrom ? (
                <div className="flex flex-col items-center justify-center h-full gap-4">
                  <div className="h-16 w-16 rounded-full bg-primary/10 flex items-center justify-center animate-pulse">
                    <GitBranch className="h-8 w-8 text-primary" />
                  </div>
                  <div className="text-center space-y-2">
                    <p className="font-medium">连接模式</p>
                    <p className="text-sm text-muted-foreground">拖拽到目标节点的连接点</p>
                  </div>
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => {
                      setConnectingFrom(null)
                      setTempConnectionEnd(null)
                      toast({
                        title: "已取消",
                        description: "连接已取消",
                      })
                    }}
                  >
                    取消连接
                  </Button>
                </div>
              ) : selectedNode ? (
                <ScrollArea className="h-full">
                  <div className="space-y-4">
                    <div className="space-y-2">
                      <Label>节点名称</Label>
                      <Input
                        value={selectedNode.label}
                        onChange={(e) => {
                          const updated = canvasNodes.map((n) =>
                            n.id === selectedNode.id ? { ...n, label: e.target.value } : n,
                          )
                          setCanvasNodes(updated)
                          setSelectedNode({ ...selectedNode, label: e.target.value })
                        }}
                      />
                    </div>
                    <div className="space-y-2">
                      <Label>节点类型</Label>
                      <Input value={selectedNode.type} disabled />
                    </div>
                    <div className="space-y-2">
                      <Label>描述</Label>
                      <Textarea placeholder="添加节点描述..." className="resize-none" rows={3} />
                    </div>
                    {selectedNode.type === "llm" && (
                      <>
                        <div className="space-y-2">
                          <Label>模型</Label>
                          <Input placeholder="gpt-4" />
                        </div>
                        <div className="space-y-2">
                          <Label>提示词</Label>
                          <Textarea placeholder="输入提示词..." className="resize-none" rows={4} />
                        </div>
                      </>
                    )}
                    {(selectedNode.type === "http" || selectedNode.type === "api") && (
                      <>
                        <div className="space-y-2">
                          <Label>API 端点</Label>
                          <Input placeholder="https://api.example.com" />
                        </div>
                        <div className="space-y-2">
                          <Label>请求方法</Label>
                          <Input placeholder="GET" />
                        </div>
                      </>
                    )}
                    <div className="pt-4 border-t">
                      <Button
                        variant="outline"
                        size="sm"
                        className="w-full bg-transparent"
                        onClick={(e) => {
                          e.stopPropagation()
                          handleConnectionStart(selectedNode.id, "right", e)
                        }}
                      >
                        <GitBranch className="mr-2 h-4 w-4" />
                        连接到其他节点
                      </Button>
                    </div>
                  </div>
                </ScrollArea>
              ) : (
                <div className="flex items-center justify-center h-full text-sm text-muted-foreground text-center px-4">
                  <div className="space-y-2">
                    <p>选择一个节点查看属性</p>
                    <p className="text-xs">从节点边缘的连接点拖拽创建连线</p>
                  </div>
                </div>
              )}
            </CardContent>
          </Card>
        </div>
      )}
    </div>
  )
}
